#include "qansieditor.h"

#include "qae_global.h"
#include "qae_qeditorwindow.h"
#include "qae_qansiwidget.h"
#include "qae_qansidecoder.h"

#include <QtCore/QtGlobal>
#include <QtGui/QApplication>

#if !defined(_OS_WIN32_) && !defined(Q_OS_WIN32)
#include <sys/stat.h>
#include <errno.h>
#include <locale.h>
#endif

#include <stdio.h>

//==============================================================================
// Crash Handler: Save the backtrace info to /var/tmp as qterm.pid.timestamp
// The line number can be retrieved using addr2line
//==============================================================================

#ifdef Q_OS_LINUX
#include <linux/limits.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <execinfo.h>
#include <signal.h>

#define QTERM_SIG_MAX_RETS 50
#define QTERM_SIG_LOG_DIR "/var/tmp"

// keep big data static to keep sig handler's stack usage to a minimum
static void *_rets[QTERM_SIG_MAX_RETS];
static char _sig_fname[PATH_MAX+1];
static char _buf[256];
void sig_fatal_init(int sig);
void sig_fatal_finish();
void sig_fatal_init();

void sig_fatal_handler (int sig)
{
    int num, fd, i;

    i = 0;

    sig_fatal_finish ();

    chdir (QTERM_SIG_LOG_DIR);

    if ((fd = creat (_sig_fname, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) < 0) {
        i = errno;
        fd = STDERR_FILENO;
    }

    num = backtrace (_rets, QTERM_SIG_MAX_RETS);

    sprintf (_buf, "Hit with signal %d! Stack trace of last %d functions:\n",
            sig, num);
    write (fd, _buf, strlen (_buf));

    backtrace_symbols_fd (_rets, num, fd);

    close (fd);

    abort ();
}

void sig_fatal_init ()
{
    time_t ut;

    time (&ut);
    strftime (_buf, sizeof (_buf), "%Y%m%d.%H%M%S", localtime (&ut));
    snprintf (_sig_fname, sizeof (_sig_fname), "%s/%s.%d.%s",
            QTERM_SIG_LOG_DIR, "qterm", getpid(), _buf);

    if (access (QTERM_SIG_LOG_DIR, F_OK))
        mkdir (QTERM_SIG_LOG_DIR, S_IRWXU | S_IRWXG | S_IRWXO);

    signal (SIGSEGV, sig_fatal_handler);
    signal (SIGBUS, sig_fatal_handler);
    signal (SIGILL, sig_fatal_handler);
    signal (SIGABRT, sig_fatal_handler);
    signal (SIGFPE, sig_fatal_handler);
}

void sig_fatal_finish ()
{
    signal (SIGSEGV, SIG_DFL);
    signal (SIGBUS, SIG_DFL);
    signal (SIGILL, SIG_DFL);
    signal (SIGABRT, SIG_DFL);
    signal (SIGFPE, SIG_DFL);
}

#endif //Q_OS_LINUX


using namespace QAnsiEditor;


QString getGBKString()
{
    QString strMsg = "";
    strMsg += "\n\n\n\n\n\n\n\n";
    strMsg += "\x1b[20C  Software is like \x1b[1;31msex\x1b[m, \r\n";
    strMsg += "\x1b[20C  It's better when it's \x1b[1;5;31mfree\x1b[m. \r\n";
    strMsg += "\n\n";
    // str1
    strMsg += "\x1b[20C  \x1b[1m";
    strMsg += "\x1b[30;40m\xd0\xc5";
    strMsg += "\x1b[31;41m\xc9\xf1";
    strMsg += "\x1b[32;42m\xcd\xe8";
    strMsg += "\x1b[33;43m\xa3\xac";
    strMsg += "\x1b[34;44m\xb5\xc3";
    strMsg += "\x1b[35;45m\xd3\xc0";
    strMsg += "\x1b[36;46m\xc9\xfa";
    strMsg += "\x1b[37;47m\xa3\xa1";
    strMsg += "\x1b[m\r\n";
    // str2
    strMsg += "\x1b[20C  ";
    strMsg += "\x1b[0;30m\xd0\x1b[1;30m\xc5";
    strMsg += "\x1b[0;31m\xc9\x1b[1;31m\xf1";
    strMsg += "\x1b[0;32m\xcd\x1b[1;32m\xe8";
    strMsg += "\x1b[0;33m\xa3\x1b[1;33m\xac";
    strMsg += "\x1b[0;34m\xb5\x1b[1;34m\xc3";
    strMsg += "\x1b[0;35m\xd3\x1b[1;35m\xc0";
    strMsg += "\x1b[0;36m\xc9\x1b[1;36m\xfa";
    strMsg += "\x1b[0;37m\xa3\x1b[1;37m\xa1";
    strMsg += "\x1b[m\r\n";

    return strMsg;
}

QString getBig5String()
{
    QString strMsg = "";
    strMsg += "\n\n\n\n\n\n\n\n";
    strMsg += "\x1b[20C  Software is like \x1b[1;31msex\x1b[m, \r\n";
    strMsg += "\x1b[20C  It's better when it's \x1b[1;5;31mfree\x1b[m. \r\n";
    strMsg += "\n\n";
    // str1
    strMsg += "\x1b[20C  \x1b[1m";
    strMsg += "\x1b[30;40m\xab\x48";
    strMsg += "\x1b[31;41m\xaf\xab";
    strMsg += "\x1b[32;42m\xa4\x59";
    strMsg += "\x1b[33;43m\xa1\x41";
    strMsg += "\x1b[34;44m\xb1\x6f";
    strMsg += "\x1b[35;45m\xa5\xc3";
    strMsg += "\x1b[36;46m\xa5\xcd";
    strMsg += "\x1b[37;47m\xa1\x49";
    strMsg += "\x1b[m\r\n";
    // str2
    strMsg += "\x1b[20C  ";
    strMsg += "\x1b[0;30m\xab\x1b[1;30m\x48";
    strMsg += "\x1b[0;31m\xaf\x1b[1;31m\xab";
    strMsg += "\x1b[0;32m\xa4\x1b[1;32m\x59";
    strMsg += "\x1b[0;33m\xa1\x1b[1;33m\x41";
    strMsg += "\x1b[0;34m\xb1\x1b[1;34m\x6f";
    strMsg += "\x1b[0;35m\xa5\x1b[1;35m\xc3";
    strMsg += "\x1b[0;36m\xa5\x1b[1;36m\xcd";
    strMsg += "\x1b[0;37m\xa1\x1b[1;37m\x49";
    strMsg += "\x1b[m\r\n";

    return strMsg;
}

QString getUTF8String()
{
    QString strMsg = "";
    strMsg += "\n\n\n\n\n\n\n\n";
    strMsg += "\x1b[20C  Software is like \x1b[1;31msex\x1b[m, \r\n";
    strMsg += "\x1b[20C  It's better when it's \x1b[1;5;31mfree\x1b[m. \r\n";
    strMsg += "\n\n";
    // str1
    strMsg += "\x1b[20C  \x1b[1m";
    strMsg += "\x1b[30;40m\xe4\xbf\xa1";
    strMsg += "\x1b[31;41m\xe7\xa5\x9e";
    strMsg += "\x1b[32;42m\xe4\xb8\xb8";
    strMsg += "\x1b[33;43m\xef\xbc\x8c";
    strMsg += "\x1b[34;44m\xe5\xbe\x97";
    strMsg += "\x1b[35;45m\xe6\xb0\xb8";
    strMsg += "\x1b[36;46m\xe7\x94\x9f";
    strMsg += "\x1b[37;47m\xef\xbc\x81";
    strMsg += "\x1b[m\r\n";
    // str2
    strMsg += "\x1b[20C  ";
    strMsg += "\x1b[0;30m\xe4\x1b[1;30m\xbf\xa1";
    strMsg += "\x1b[0;31m\xe7\x1b[1;31m\xa5\x9e";
    strMsg += "\x1b[0;32m\xe4\x1b[1;32m\xb8\xb8";
    strMsg += "\x1b[0;33m\xef\x1b[1;33m\xbc\x8c";
    strMsg += "\x1b[0;34m\xe5\x1b[1;34m\xbe\x97";
    strMsg += "\x1b[0;35m\xe6\x1b[1;35m\xb0\xb8";
    strMsg += "\x1b[0;36m\xe7\x1b[1;36m\x94\x9f";
    strMsg += "\x1b[0;37m\xef\x1b[1;37m\xbc\x81";
    strMsg += "\x1b[m\r\n";

    return strMsg;
}

int main(int argc, char *argv[])
{

    QApplication app(argc, argv);
    app.setApplicationName("QTerm");

#ifdef Q_OS_LINUX
    sig_fatal_init();
#endif


    QGlobal::instance()->loadSettings();
#ifdef Q_OS_WIN32
    // add codec path
    QString codecPath = app.applicationDirPath() + QString("/codecs");
    app.addLibraryPath(codecPath);
#endif

    QEditorWindow *win = new QEditorWindow;
    win->setAttribute(Qt::WA_DeleteOnClose);
    win->setMinimumSize(800, 500);
    win->show();

    QString strMsg;
    switch (QGlobal::instance()->inputEncoding()) {
    case QGlobal::GBK:
        strMsg = getGBKString();
        break;
    case QGlobal::Big5:
        strMsg = getBig5String();
        break;
    case QGlobal::UTF8:
        strMsg = getUTF8String();
        break;
    }

    // decode
    QByteArray a = strMsg.toLatin1();
    win->getAnsiWidget()->setContent(strMsg.toLatin1(), QGlobal::instance()->inputEncoding());

    int res = app.exec();
    return res;
}
